#pragma once

#include <windows.h>   
#include <stdio.h>   
#include <mmsystem.h>   
#pragma comment(lib, "winmm.lib") 
#include "MutableBuffer.h"
#include "AudioEngineInterface.h"

#include "common\inc\thread\locksection.h"
#include "common\inc\thread\lock.h"
using fs::thread::LockSection;
using fs::thread::Lock;

#include <queue>
using std::queue;

#ifdef _DEBUG
#include "vld.h"
#endif

#define FRAGMENT_SIZE 1024              // cache size
#define FRAGMENT_NUM 4                  // cache count

class AudioEngine
{
public:
	AudioEngine(AudioEngineInterface* audioEngineInterface);
	~AudioEngine(void);

	void setAudioEngineInterface(AudioEngineInterface* audioEngineInterface);
	AudioEngineInterface* audioEngineInterface() const;

	/****************Record***************/
	bool startRecord(bool recordAndPlay=false);
	void stopRecord();
	const WAVEFORMATEX& waveInFormateX() const;
	MutableBuffer* waveInBuffer() const;
	void addNextWaveInBuffer(const void* newBuffer,int newBufferSize);
	static void CALLBACK waveInProc(HWAVEIN hwi,        
		UINT uMsg,           
		DWORD_PTR dwInstance,    
		DWORD_PTR dwParam1,    
		DWORD_PTR dwParam2     ); 

	/****************Play***************/
	bool startPlay();
	void stopPlay();
	void setWaveOutVolumePercent(float percent);
	void setWaveOutFormateX(WAVEFORMATEX waveOutFormateX);
	void addWaveOutBuffer(const MutableBuffer* buffer);
	void addWaveOutBuffer(const void* newBuffer,int newBufferSize);
	static void CALLBACK waveOutProc(  HWAVEOUT hwo,     
		UINT uMsg,           
		DWORD_PTR dwInstance,     
		DWORD_PTR dwParam1,      
		DWORD_PTR dwParam2     );

	//wave headed buffer
	static bool getWaveHeadedBuffer(const WAVEFORMATEX& wavform,const void* waveDataBuffer,unsigned int waveDataBufferSize,MutableBuffer* waveHeadedBuffer);
	static bool getWaveBuffer(WAVEFORMATEX& wavform,MutableBuffer* waveDataBuffer,const void* waveHeadedBuffer,unsigned int waveHeadedBufferSize);

private:
	void playNextBuffer();
	static void CallRun(LPVOID p);
	void stopWaveOut();

private:
	AudioEngineInterface* m_audioEngineInterface;

	HWAVEIN m_hWaveIn;
	WAVEFORMATEX m_waveInFormateX;
	WAVEHDR m_waveInHdrArray[FRAGMENT_NUM]; //wave data block header,prepare buffer for wave in
	MutableBuffer* m_waveInBuffer;
	bool m_isRecoding;

	HWAVEOUT m_hWaveOut;  
	WAVEFORMATEX m_waveOutFormateX;
	queue<MutableBuffer*> m_waveOutBufferQueue;
	WAVEHDR m_waveOutHdr;  
	bool m_isPlaying;
	DWORD m_threadId;
	HANDLE m_hSingleObjectEvent;
	HANDLE m_hWaveInSingleObjectEvent;
	MutableBuffer* m_waveOutTempBuffer;
};

